/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Armin Lunkeit
 *
 * This implementation is part of math-core
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
//
//  main.cpp
//  graph-tool
//
//  Created by Armin Lunkeit on 15.02.14.
//  Copyright (c) 2014 Armin Lunkeit. All rights reserved.
//

#include <iostream>
#include <vector>
#include <memory>

#include "../math-core/matrix.h"
#include "../math-core/fraction.h"
#include "../math-core/macros.h"
#include "../math-core/multigraph.h"

#include "catreader.h"

void testFraction()
{
    Fraction f1( 1, 2 );
    Fraction f2( 2, 4 );
    Fraction f3( 3, 6 );
    Fraction f4( 4, 6 );
    
    std::cout << f1 + f2 << std::endl;
    std::cout << f1 - f2 << std::endl;
    std::cout << f1 - f4 << std::endl;
    std::cout << f1 + f4 << std::endl;
    std::cout << f1 / f2 << std::endl;
    std::cout << f4 / f1 << std::endl;
    std::cout << f1 * f2 << std::endl;
    std::cout << f3 * f4 << std::endl;
    
    bool isgreater = f4 > f3;
    
    std::cout << "is greater: " << isgreater << std::endl;
    
    Fraction sf( "1/2" );
    std::cout << sf << std::endl;
    
    Fraction sf1( "3" );
    std::cout << sf1 << std::endl;
    
    Fraction df1( 1.3 );
    std::cout << "df1 := " << df1 << std::endl;
    
    Fraction df2( 3.141579432156 );
    std::cout << "df2 := " << df2 << std::endl;
    
    Fraction tf = LD(12, 5); // -> equal to (long double)12/(long double)5
    std::cout << "tf := " << tf << std::endl;
    
    Fraction tf1 = 2.4;
    std::cout << "tf1 := " << tf1 << std::endl;
    
    tf1 *= 3;
    std::cout << "tf1 after multiplication := " << tf1 << std::endl;
    
    // test some more operators implemented for the fraction representation
    std::cout << "f1 += 2 := " << (f1 += (uint32_t)2) << std::endl;
    std::cout << "f1 += -4/2 := " << (f1 += Fraction( -4, 2) ) << std::endl;
    
    Fraction d = f3 + f4;
    std::cout << "d := " << f3 << " + " << f4 << " = " << d << std::endl;
    
    d -= 2;
    std::cout << "d := d -= 2 = " << d << std::endl;
    

}

void testMatrix()
{
    Matrix m0( 3,3 );
    Matrix m1( 5,5 );
    
    std::cout << "m0 := " << m0 << std::endl;
    std::cout << "m1 := " << m1 << std::endl;
    
    // now test index operator and assignment of values
    *m0[0][0] = (long double)12/5;
    
    std::cout << "m0 := " << m0 << std::endl;
    
    long double val = *m0[0][0];
    Fraction frac = *m0[0][0];
    
    std::cout << "value := " << val << std::endl;
    std::cout << "frac := " << frac << std::endl;
    
    // fill m0  with sample values
    for( int i = 0; i < 3; i++ )
        for( int j = 0; j < 3; j++ )
            *m0[i][j] = LD(j,1);
    
    std::cout << m0 << std::endl;
    
    m0.transpose();
    
    std::cout << m0 << std::endl;
    
    m0.multiplyScalar(3);
    
    std::cout << m0 << std::endl;
    
    Matrix fracs = m0.getColumn(1);
    
    std::cout << "fracs := " << fracs << std::endl;
    
    Matrix frcs2 = m0;
    
    std::cout << "frcs2 := " << frcs2 << std::endl;
    
    Matrix r = m0.getRow( 1 );
    
    std::cout << "r := " << r << std::endl;
    
    std::cout << "m0 := " << m0 << std::endl;
    
    Matrix mult = m0 * m0;
    
    std::cout << mult << std::endl;
    
    Matrix mm1( 2, 2 );
    *mm1[ 0 ][ 0 ] = 1;
    *mm1[ 0 ][ 1 ] = 1;
	*mm1[ 1 ][ 0 ] = 1;
    *mm1[ 1 ][ 1 ] = 1;
    
    Matrix mm2( 2, 2 );
    *mm2[ 0 ][ 0 ] = 1;
    *mm2[ 0 ][ 1 ] = 1;
    *mm2[ 1 ][ 0 ] = 3;
    *mm2[ 1 ][ 1 ] = 3;
    
    std::cout << mm1 * mm2 << std::endl;

	try
	{
		mm1.getRow(87);
	}
	catch (std::exception& e)
	{
		std::cout << e.what() << std::endl;
	}
	

	std::cout << "-----------------------------------" << std::endl;
}

#if 0
void testVArray()
{
	typedef std::shared_ptr<Fraction> PFraction;
	typedef std::vector<PFraction> PFArray;
	typedef std::vector< PFArray > FMatrix;
	//typedef std::vector< std::vector< std::shared_ptr<Fraction> > > FMatrix;
	FMatrix arr;

	arr.resize(10);

	for (FMatrix::iterator iter = arr.begin(); iter != arr.end(); iter++)
		iter->resize(10);

	size_t c = 1;
	for (FMatrix::iterator iter = arr.begin(); iter != arr.end(); iter++)
	{
		
		size_t x = 1;

		for (PFArray::iterator iiter = iter->begin(); iiter != iter->end(); iiter++)
		{
			*iiter = std::make_shared<Fraction>(c, x);

			std::cout << "c := " << c << "x := " << x;

			x += 1;
		}
		std::cout << std::endl;

		c += 1;
	}

	for (FMatrix::iterator iter = arr.begin(); iter != arr.end(); iter++)
	{
		for (PFArray::iterator iiter = iter->begin(); iiter != iter->end(); iiter++)
		{
			std::cout << **iiter << " ";
		}
		std::cout << std::endl;

		c += 1;
	}

	Fraction f1 = *arr[0][0];

	std::cout << "f1 := " << f1 << std::endl;
}
#endif

void testGraphBase()
{
    std::cout << "----------------------------------------------------------" << std::endl;
    std::cout << "------- test routine for basic graph implementation ------" << std::endl;
    std::cout << "----------------------------------------------------------" << std::endl;
    
    MultiGraph graph;
    
    PVertex v1 = std::make_shared<Vertex>();
    PVertex v2 = std::make_shared<Vertex>();
    
    PEdge e1 = std::make_shared<Edge>( v1, v2 );
    
    graph.addVertex(v1);
    graph.addVertex(v2);
    graph.addEdge(e1);
    
    PAttributeVertex v3 = std::make_shared<AttributeVertex>( 1 );
    graph.addVertex( v3 );
    
    std::string file = "/Volumes/Daten/Promotion/Development/Java/goldbergtarjan/cat/maxflows/V5CD.cat";
    
    PMultiGraph pgraph = initFromCAT(file);
}

int main(int argc, const char * argv[])
{

    testFraction();
    testMatrix();
    testGraphBase();
    
    return 0;
}

